﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Infinity.Common;
using Infinity.Common.Extensions;
using Infinity.Common.Logger;
using Infinity.Expressions;
using Infinity.Expressions.ExpressionFactory;
using Infinity.Expressions.Utilities;
using Infinity.Parser.Lexical;
using Infinity.Parser.Syntax;
using Infinity.Statements;
using Infinity.Statements.StatementFactory;
using Infinity.Statements.Utilities;

namespace Infinity.Compilers
{
	/// <summary>
	/// Compiler for Infinity language
	/// </summary>
	public class Compiler : ICompiler
	{
		private SyntaxParser m_SyntaxParser { get; set; }
		private LexicalParser m_LexicalParser { get; set; }
		private IStatementFactory m_StatementFactory { get; set; }

		public ITypeManager TypeManager { get; set; }
		public ICastManager CastManager { get; set; }
		public IScopeManager ScopeManager { get; set; }

		public ILogger Logger { get; protected set; }

		/// <summary>
		/// It returns errors of parser
		/// </summary>
		public List<string> Errors
		{
			get { return m_LexicalParser.ErrorList; }
		}

		/// <summary>
		/// Default constructor
		/// </summary>
		public Compiler()
			: this(DebugLogger.Instance)
		{
		}

		/// <summary>
		/// Default constructor. You can add a logger for compiling.
		/// </summary>
		public Compiler(ILogger logger)
		{
			Ensure.NotNull("logger", logger);
			Logger = logger;
			Initialize();
		}

		/// <summary>
		/// It initialize the class
		/// </summary>
		private void Initialize()
		{
			TypeManager = new TypeManager();
			CastManager = new CastManager();
			ScopeManager = new ScopeManager();

			m_StatementFactory = new StatementFactory(this)
				                     {
					                     Logger = Logger
				                     };

			m_LexicalParser = new LexicalParser();
			m_SyntaxParser = new SyntaxParser(m_LexicalParser, m_StatementFactory)
				                 {
					                 Logger = Logger
				                 };
		}

		/// <summary>
		/// It compiles the current source code
		/// </summary>
		public bool Compile(string source)
		{
			Ensure.NotNull("source", source);

			//try
			{
				m_LexicalParser.SetSource(source, 0);
				m_SyntaxParser.Parse();

				if (Logger.IsNotNull())
					foreach (var error in m_LexicalParser.ErrorList)
						Logger.Error(error);
			}
			/*catch (Exception e)
			{
				if (Logger.IsNotNull())
					Logger.Error(e.Message);
				return false;
			}*/

			return true;
		}
	}
}